﻿#pragma once

#include <learn/geom/nurbs.h>

namespace xi
{

namespace geom
{

template <std::size_t N> class Geom_Curve
{
    static_assert(N > 0, "N must be greater than 0");
    using Vec = VecT<N, double>;

  public:
    /**
     * @brief 计算曲线上点的位置
     *
     * @param[in] t
     * @return Vec
     */
    virtual Vec d0(double t) const = 0;

    /**
     * @brief 计算曲线上点的位置和导数
     *
     * @param[in] t
     * @return std::array<Vec, 2>
     */
    virtual std::array<Vec, 2> d1(double t) const = 0;

    /**
     * @brief 计算曲线上点的位置、导数和二阶导数
     *
     * @param[in] t
     * @return std::array<Vec, 3>
     */
    virtual std::array<Vec, 3> d2(double t) const = 0;

    /**
     * @brief 计算曲线上点的位置、导数、二阶导数和三阶导数
     *
     * @param[in] t
     * @return std::array<Vec, 4>
     */
    virtual std::array<Vec, 4> d3(double t) const = 0;

    /**
     * @brief 起始参数
     *
     * @return double
     */
    virtual double first_param() const = 0;

    /**
     * @brief 终止参数
     *
     * @return double
     */
    virtual double last_param() const = 0;

    /**
     * @brief 将曲线序列化为 json 格式
     *
     * @return utils::Json
     */
    virtual utils::Json dump_json() const = 0;

    /**
     * @brief 计算曲线上点的位置
     *
     * @param[in] t
     * @return Vec
     */
    Vec value(double t) const
    {
        return d0(t);
    }

    /**
     * @brief 起点
     *
     * @return Vec
     */
    Vec start_point() const
    {
        return d0(first_param());
    }

    /**
     * @brief 终点
     *
     * @return Vec
     */
    Vec end_point() const
    {
        return d0(last_param());
    }
};

} // namespace geom

} // namespace xi
